#include <Windows.h>
#include <tchar.h>
#include "resource.h"
#include <CommCtrl.h>

#define		WM_INITMONITOR		(WM_APP + 1000)

struct SMonitorInfo {
	int			nSize;
	TCHAR		szFilePath[MAX_PATH];
	HANDLE		hHandle;
	HWND		hLstView;
};

void RetrieveDriveName(TCHAR* szDriveName, TCHAR* szItem)
{
	if (NULL != szItem && NULL != szDriveName)
	{
		TCHAR* szPos = _tcsstr(szItem, _T(":\\"));
		if (NULL != szPos && szPos > szItem)
		{
			memcpy(szDriveName, --szPos, 3 * sizeof(TCHAR));
			szDriveName[3] = _T('\0');
		}
	}

	return;
}

DWORD CALLBACK ChangeMonitorProc(LPVOID lpData)
{
	SMonitorInfo* pMonitorInfo = (SMonitorInfo*)lpData;
	if (NULL != pMonitorInfo)
	{		
		FILE_NOTIFY_INFORMATION arFileNotifyInfo[1024];
	
		DWORD dwBytesReturn;
		DWORD dwFilter = FILE_NOTIFY_CHANGE_SECURITY|FILE_NOTIFY_CHANGE_CREATION|
						 FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME;
						 //|FILE_NOTIFY_CHANGE_LAST_WRITE|FILE_NOTIFY_CHANGE_LAST_ACCESS|
						 //FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_ATTRIBUTES
		int nItem = 0;
		while(ReadDirectoryChangesW(pMonitorInfo->hHandle, &arFileNotifyInfo, sizeof(arFileNotifyInfo), TRUE, dwFilter, &dwBytesReturn, NULL, NULL))
		{
			TCHAR szPrompt[MAX_PATH]	= {0};			
			DWORD nIndex = 0; 		
			do {
				switch (arFileNotifyInfo[nIndex].Action)
				{
					case FILE_ACTION_ADDED:					_tcscpy(szPrompt, _T("Added file"));		break;
					case FILE_ACTION_MODIFIED:				_tcscpy(szPrompt, _T("Modify file"));		break;			
					case FILE_ACTION_REMOVED:				_tcscpy(szPrompt, _T("Remove file"));		break;
					case FILE_ACTION_RENAMED_OLD_NAME:		_tcscpy(szPrompt, _T("Rename file"));		break;	
					case FILE_ACTION_RENAMED_NEW_NAME:		_tcscpy(szPrompt, _T("Rename file"));		break;
				}	
				
				arFileNotifyInfo[nIndex].FileName[arFileNotifyInfo[nIndex].FileNameLength/2] = NULL;
				_stprintf(szPrompt, _T("%s: %s\n"), szPrompt, arFileNotifyInfo[nIndex].FileName);
				LVITEM lvItem		= {0};
				lvItem.mask			= LVIF_TEXT;
				lvItem.iItem		= 0;
				lvItem.iSubItem		= 0;
				lvItem.pszText		= szPrompt;
				lvItem.cchTextMax	= MAX_PATH;
				nItem = ListView_InsertItem(pMonitorInfo->hLstView, &lvItem);
				nIndex++;
			} while (!arFileNotifyInfo[nIndex].NextEntryOffset);
		}
	}
	
	return 0;
}

int CALLBACK DlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND	 hListView	= NULL;
	static HANDLE hThread	= NULL;
	static SMonitorInfo MonitorInfo;

	switch (nMsg)
	{
		case WM_INITDIALOG:
		{
			SetWindowText(hDlg, _T("Demo0065"));
			UINT nWidth		= GetSystemMetrics(SM_CXSCREEN);
			UINT nHeight	= GetSystemMetrics(SM_CYSCREEN);
			RECT rtClient;
			GetClientRect(hDlg, &rtClient);
			SetWindowPos(hDlg, NULL, (nWidth - (rtClient.right - rtClient.left)) / 2, (nHeight - (rtClient.bottom - rtClient.top)) / 2, 0, 0, SWP_NOSIZE);
			
			//==: init listview
			RECT rtListView;
			GetClientRect(hListView, &rtListView);
			TCHAR szText[MAX_PATH];
			hListView = GetDlgItem(hDlg, IDC_LSTREPORT);
			LVCOLUMN lvCol;
			lvCol.mask		= LVCF_TEXT|LVCF_WIDTH;
			lvCol.pszText	= szText;
			lvCol.cchTextMax= MAX_PATH;	
			lvCol.cx		= rtListView.right - rtListView.left - 20;
			ListView_InsertColumn(hListView, 0, &lvCol);
			ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
		
			TCHAR szBuffer[MAX_PATH];
			GetLogicalDriveStrings(MAX_PATH, szBuffer);
			TCHAR* szPos = szBuffer;
			while (_T('\0') != *szPos)
			{
				TCHAR szDriveName[32];
				TCHAR szVolumeBuf[MAX_PATH];
				TCHAR szItemData[MAX_PATH];
				_tcscpy(szDriveName, szPos);
				GetVolumeInformation(szDriveName, szVolumeBuf, MAX_PATH, NULL, NULL, NULL, NULL, 0);
				_stprintf(szItemData, _T("%s - %s"), szDriveName, szVolumeBuf);
				SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_ADDSTRING, 0, (LPARAM)szItemData);
				
				szPos += _tcslen(szDriveName);
				szPos ++;
			}

			break;
		}
		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDC_BTNCLEAR:
				{
					ListView_DeleteAllItems(hListView);
					break;
				}				
				case IDC_BTNSTART:
				{
					TCHAR szBtnName[MAX_PATH];
					GetDlgItemText(hDlg, IDC_BTNSTART, szBtnName, MAX_PATH);
					if (0 == _tcsicmp(szBtnName, _T("Start")))
					{
						EnableWindow(GetDlgItem(hDlg, IDC_BTNSTART), FALSE);

						TCHAR szItem[64];
						int nItem = SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_GETCURSEL, 0, 0);					
						SendDlgItemMessage(hDlg, IDC_LSTDRIVES, LB_GETTEXT, (WPARAM)nItem, (LPARAM)szItem);
						RetrieveDriveName(MonitorInfo.szFilePath, szItem);
						MonitorInfo.hLstView= hListView;	
						MonitorInfo.hHandle = CreateFile(MonitorInfo.szFilePath, 
														 FILE_LIST_DIRECTORY, 
														 FILE_SHARE_READ|FILE_SHARE_DELETE, 
														 NULL, 
														 OPEN_EXISTING, 
														 FILE_FLAG_BACKUP_SEMANTICS,
														 NULL);
						hThread = CreateThread(NULL, NULL, ChangeMonitorProc, (LPVOID)&MonitorInfo, NULL, NULL);
					}
					
									
					break;
				}
				case IDC_BTNEXIT:
				{
					if (NULL != MonitorInfo.hHandle)
					{
						CloseHandle(MonitorInfo.hHandle);
						MonitorInfo.hHandle	= NULL;
					}
					TerminateThread(hThread, 0);
					hThread = NULL;
					
					EndDialog(hDlg, 0);
					break;
				}
			}
			break;
		}
		case WM_CLOSE:
		{
			PostQuitMessage(0);
			break;
		}
	}

	return 0;
}

BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);

	return TRUE;
}